/* board.c - Board-specific hooks */

/*
 * Copyright (c) 2017 Intel Corporation
 * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <stdio.h>

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"

#include "driver/gpio.h"
#include "esp_log.h"
#include "board.h"
#include "esp_ble_mesh_provisioning_api.h"

#define TAG "BOARD"

#define INTR_FLAG_DEFAULT 0

static xQueueHandle s_evt_queue;

struct _led_state led_state[] = {
    { LED_OFF, LED_OFF, GPIO_NUM_25, " "   },
    { LED_OFF, LED_OFF, GPIO_NUM_26, " "   },
    { LED_OFF, LED_OFF, GPIO_NUM_27, " "   },
    { LED_OFF, LED_OFF, GPIO_NUM_33, " "   },
    { LED_OFF, LED_OFF, GPIO_NUM_32, " "   },
    { LED_OFF, LED_OFF, GPIO_NUM_22, " "   },
    { LED_OFF, LED_OFF, GPIO_NUM_23, " "   },
    { LED_OFF, LED_OFF, GPIO_NUM_14, " "   },
    { LED_OFF, LED_OFF, GPIO_NUM_12, " "   },
    { LED_OFF, LED_OFF, GPIO_NUM_18, " "   },
    { LED_OFF, LED_OFF, GPIO_NUM_17, " "   },
    { LED_OFF, LED_OFF, GPIO_NUM_16, " "   },
};

void board_output_number(esp_ble_mesh_output_action_t action, uint32_t number)
{
    ESP_LOGI(TAG, "Board output number %d", number);
}

void board_prov_complete(void)
{
    board_led_operation(LED_G, LED_OFF);
}

// void board_led_operation(uint8_t pin, uint8_t onoff)
// {
//     for (int i = 0; i < sizeof(led_state)/sizeof(led_state[0]); i++) {
//         if (led_state[i].pin != pin) {
//             continue;
//         }
//         if (onoff == led_state[i].previous) {
//             ESP_LOGW(TAG, "led %s is already %s",
//                      led_state[i].name, (onoff ? "on" : "off"));
//             return;
//         }
//         gpio_set_level(pin, onoff);
//         led_state[i].previous = onoff;
//         return;
//     }

//     ESP_LOGE(TAG, "LED is not found!");
// }

static void board_led_init(void)
{
    for (int i = 0; i < sizeof(led_state)/sizeof(led_state[0]); i++) {
        gpio_pad_select_gpio(led_state[i].pin);
        gpio_set_direction(led_state[i].pin, GPIO_MODE_OUTPUT);
        gpio_set_level(led_state[i].pin, LED_OFF);
        led_state[i].previous = LED_OFF;
    }
}

static void IRAM_ATTR switch_isr_handler(void *arg)
{
    uint32_t gpio_num = (uint32_t) arg;
    xQueueSendFromISR(s_evt_queue, &gpio_num, NULL);
}

static void switch_key_init(uint32_t key)
{
    gpio_config_t io_conf;
    io_conf.intr_type = GPIO_INTR_NEGEDGE;
    io_conf.pin_bit_mask = 1 << key;
    io_conf.mode = GPIO_MODE_INPUT;
    io_conf.pull_up_en = 1;
    io_conf.pull_down_en = 0;
    gpio_config(&io_conf);

    gpio_set_intr_type(key, GPIO_INTR_NEGEDGE);
    gpio_install_isr_service(INTR_FLAG_DEFAULT);
    gpio_isr_handler_add(key, switch_isr_handler, (void *)key);
}

static void switch_task_entry(void *arg)
{
    while (1) {
        uint32_t io_num;
        if (xQueueReceive(s_evt_queue, &io_num, portMAX_DELAY) == pdTRUE) {
            uint8_t onoff = led_state[0].previous;
            ESP_LOGI(TAG, "GPIO[%d] intr, val: %d", io_num, gpio_get_level(io_num));
            board_led_operation(LED_R, !onoff);
            led_state[0].previous = !onoff;
            //TODO: publish state change message
        }
    }
}

static void switch_init(gpio_num_t gpio_num)
{
    s_evt_queue = xQueueCreate(3, sizeof(uint32_t));
    if (!s_evt_queue) {
        return;
    }

    BaseType_t ret = xTaskCreate(switch_task_entry, "switch", 4096, NULL, 4, NULL);
    if (ret == pdFAIL) {
        goto fail;
    }

    switch_key_init(gpio_num);
    return;

fail:
    vQueueDelete(s_evt_queue);
}

void board_init(void)
{
    board_led_init();
    // switch_init(GPIO_NUM_18);
}

